package com.bbbug.coree.controller;


import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bbbug.coree.entity.*;
import com.bbbug.coree.service.*;

import com.bbbug.coree.task.SongTask;
import com.bbbug.coree.utils.MiscUtil;
import com.bbbug.coree.utils.SpringUtils;
import com.bbbug.coree.websocketservice.core;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@CrossOrigin(origins = "${myweb-path}")
@EnableCaching
@RequestMapping("api/song")
public class SongController {
    RedisTemplate redisTemplate = SpringUtils.getBean("redistemp");
    @Autowired
    SongService songService;
    @Autowired
    SubscribeinfoService subscribeinfoService;
    @Autowired
    LrcinfoService lrcinfoService;
    @Autowired
    UserinfoService userinfoService;
    @Autowired
    RooominfoService roominfoService;
    @Autowired
    MessageinfoService messageinfoService;

    @RequestMapping("addSong")
    ReturnData addSong(@RequestBody JSONObject mp) {
        String access_token = mp.getString("access_token");
        String user1 = MiscUtil.verifyToken(access_token);
        String room_id = mp.getString("room_id");
        Roominfo roominfo = roominfoService.queryById(Integer.parseInt(room_id));
        if (roominfo.getRoom_type() == 0) {
            return new ReturnData(401, "文字聊天房不能点歌", null);
        }
        BoundListOperations<String, Object> roomops = redisTemplate.boundListOps(room_id);
        Long size = roomops.size();
        if (user1 == null) {
            return new ReturnData(401, "点歌失败 请先登陆", null);
        } else if (songisexit(room_id, mp.getLong("mid"))) {
            return new ReturnData(403, "这首歌正在等待播放ing", null);
        } else if ((roominfo.getRoom_addcount() != null && roominfo.getRoom_addcount() != -1) && roominfo.getRoom_addcount() <= size) {
            return new ReturnData(403, "达到歌曲上限！ 请联系管理员加上限或者乖乖等待这一首放完", null);
        } else if (roominfo.getRoom_addsongcd() != null && roominfo.getRoom_addsongcd() != -1) {
            BoundHashOperations addsongcd = redisTemplate.boundHashOps("addsongcd");
            HashMap<String, Long> songcd = (HashMap<String, Long>) addsongcd.get(room_id);
            if (songcd == null) {
                songcd = new HashMap<>();
                songcd.put(user1, System.currentTimeMillis());
            } else {
                if (songcd.get(user1) == null) {
                    songcd.put(user1, System.currentTimeMillis());
                } else if (songcd.get(user1) + roominfo.getRoom_addsongcd() * 1000 < System.currentTimeMillis()) {
                    songcd.put(user1, System.currentTimeMillis());
                } else {
                    return new ReturnData(403, "还有 " + ((songcd.get(user1) + roominfo.getRoom_addsongcd() * 1000 - System.currentTimeMillis()) / 1000) + "秒才能点", null);
                }
            }
            addsongcd.put(room_id, songcd);
        }
        BoundHashOperations shutdown = redisTemplate.boundHashOps("songdown");
        HashMap<String, Long> jinyan = (HashMap<String, Long>) shutdown.get(room_id);
        if (jinyan != null && jinyan.get(user1) != null) {
            if (jinyan.get(user1) >= System.currentTimeMillis()) {
                return new ReturnData(403, "你被禁歌中！", null);
            } else {
                jinyan.remove(user1);
            }
        }
        Object mid = mp.get("mid");
        songService.updateSong(Integer.parseInt(mid.toString()));
        Songinfo songinfo = querybyid(mid);
        JSONObject item = new JSONObject();
        if (size == 0) {
            long l = System.currentTimeMillis();
            item.put("at", false);
            item.put("since", l / 1000);
            item.put("song", songinfo);
            item.put("end", (l + Long.valueOf(songinfo.getLength()) * 1000) / 1000);
            item.put("type", "playSong");
            item.put("story", null);
            item.put("count", size + 1);
            item.put("user", userinfoService.queryById(Integer.parseInt(user1)));
            messageinfoService.sendMessage(room_id, item.toJSONString());
        } else {
            JSONObject jsonObject = JSON.parseObject(roomops.index(size - 1).toString());
            Long since = Long.valueOf(jsonObject.get("end").toString());
            Long length = Long.valueOf(songinfo.getLength().toString());
            item.put("end", since + length);
            item.put("since", since);
            item.put("song", songinfo);
            item.put("type", "addSong");
            item.put("story", null);
            item.put("count", size + 1);
            item.put("user", userinfoService.queryById(Integer.parseInt(user1)));
            messageinfoService.sendMessage(room_id, item.toJSONString());
        }
        roomops.rightPush(item.toJSONString());
        songinfo.setHot(0);
        item.put("song", JSONUtil.toJsonStr(songinfo));
        item.remove("user");
        item.remove("since");
        item.remove("end");
        redisTemplate.opsForSet().add("history", item.toJSONString());
        List<Subscribeinfo> t1 = subscribeinfoService.queryForBoth(Integer.valueOf(mp.get("mid").toString()), Integer.parseInt(user1));
        if (t1.size() == 0) {
            subscribeinfoService.insert(Integer.parseInt(mp.get("mid").toString()), Integer.parseInt(user1), 1);
        } else {
            subscribeinfoService.update(Integer.valueOf(mp.get("mid").toString()), Integer.parseInt(user1));
        }
        return new ReturnData(200, "歌曲添加成功", mp.get("info"));
    }

    @RequestMapping("playSong")
    public ReturnData playSong(@RequestBody JSONObject mp) {
        return addSong(mp);
    }

    public Songinfo querybyid(Object id) {
        return songService.queryByMid(Long.parseLong(id.toString()));
    }

    public Object querybykey(String key) {
        List<JSONObject> res = searchInDb(key);
        JSONObject jsonObject = JSON.parseObject(MiscUtil.getres(key));
        JSONObject data = jsonObject.getJSONObject("data");
        if (data == null || data.equals(null)) {
            return res;
        } else {
            JSONArray list = data.getJSONArray("list");
            int len = list.size();
            for (int i = 0; i < len; i++) {
                JSONObject jtp = list.getJSONObject(i);
                JSONObject jitem = new JSONObject();
                jitem.put("pic", jtp.get("pic"));
                jitem.put("mid", jtp.get("rid"));
                jitem.put("name", jtp.get("name"));
                jitem.put("singer", jtp.get("artist"));
                jitem.put("length", jtp.get("duration"));
                res.add(jitem);
                /*jdbcTemplate.queryForList("select * from songinfo where mid=?",jtp.get("rid")).size()==0*/
                if (songService.queryByMid(Long.parseLong(jtp.get("rid").toString())) == null) {
                    Songinfo songinfo = new Songinfo();
                    songinfo.setMid(Long.parseLong(jtp.get("rid").toString()));
                    songinfo.setName(jtp.get("name").toString());
                    songinfo.setPic(jtp.get("pic").toString());
                    songinfo.setSinger(jtp.get("artist").toString());
                    songinfo.setLength(Integer.parseInt(jtp.get("duration").toString()));
                    songinfo.setHot(0);
                    songService.insert(songinfo);
                }
            }
            return res;

        }
    }

    public List<JSONObject> searchInDb(String key) {
        List<Songinfo> songinfos = songService.queryByUserUpload(key);
        List<JSONObject> res = new ArrayList<>();
        for (Songinfo songinfo : songinfos) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("pic", songinfo.getPic());
            jsonObject.put("mid", songinfo.getMid());
            jsonObject.put("name", songinfo.getName());
            jsonObject.put("singer", songinfo.getSinger());
            jsonObject.put("length", songinfo.getLength());
            res.add(jsonObject);
        }
        return res;
    }

    @RequestMapping("/playurl")
    public void getplayurl(HttpServletResponse response, String mid) throws IOException {
        long l = Long.parseLong(mid);
        if (l < 0) {
            Songinfo songinfo = songService.queryByMid(l);
            response.sendRedirect(songinfo.getUrl());
        }
        String body = HttpUtil.createGet("http://www.kuwo.cn/api/v1/www/music/playUrl?mid=" + mid + "&type=convert+url3&br=320kmp3").execute().body();
        JSONObject jsonObject = JSON.parseObject(body);
        response.sendRedirect(jsonObject.getJSONObject("data").get("url").toString());
    }

    @RequestMapping("search")
    @Cacheable(value = "search_key", key = "#mp.get(\"keyword\")", condition = "#mp.get(\"keyword\")!=null")
    public ReturnData search(@RequestBody JSONObject mp) {
        if (mp.get("keyword") == null || mp.getInteger("isHots") == 1) {
            return new ReturnData(200, "ok", songService.queryByLimit());
        } else {
            return new ReturnData(200, "ok", querybykey(mp.getString("keyword")));
        }
    }

    @RequestMapping("/getLrc")//太大了不使用缓存 直接存储于数据库中
    public String getLrc(@RequestBody JSONObject mid) {
        Long id = mid.getLong("mid");
        if (id < 0) {
            JSONObject msg = new JSONObject();
            msg.put("code", 200);
            msg.put("msg", "成功");
            msg.put("data", Arrays.asList(MapUtil.builder().put("lineLyric", "这首是用户上传的歌曲，暂无歌词")
                    .put("time", "0.0").build()));
            return msg.toJSONString();
        }
        Lrcinfo lrcinfo = lrcinfoService.queryById(id.intValue());
        if (lrcinfo == null) {
            String mid2 = MiscUtil.getLRC(mid.get("mid").toString());
            lrcinfoService.insert(id.intValue(), mid2);
            return mid2;
        } else {
            String lrc = lrcinfo.getLrc();
            return lrc;
        }
    }

    @RequestMapping("songList")
    ReturnData songList(@RequestBody Map mp) {
        List<Object> r1 = redisTemplate.opsForList().range(mp.get("room_id").toString(), 1, -1);
        JSONArray jsonArray = new JSONArray();
        for (Object tp1 : r1) {
            jsonArray.add(JSONObject.parseObject(tp1.toString()));
        }
        return new ReturnData(200, "", jsonArray);
    }

    @RequestMapping("addMySong")
    ReturnData addMySong(@RequestBody Map mp) {
        String userid = MiscUtil.verifyToken(mp.get("access_token").toString());
        if (userid == null) {
            return new ReturnData(403, "没权限QWQ", null);
        } else {
            List<Subscribeinfo> subscribeinfo = subscribeinfoService.queryForBoth(Integer.valueOf(mp.get("mid").toString()), Integer.parseInt(userid));
            if (subscribeinfo != null) {
                subscribeinfoService.update(Integer.valueOf(mp.get("mid").toString()), Integer.parseInt(userid));
            }
            subscribeinfoService.insert(Integer.parseInt(mp.get("mid").toString()), Integer.parseInt(userid), 1);
            return new ReturnData(200, "添加至歌单成功", null);
        }
    }

    @RequestMapping("mySongList")
    ReturnData mySongList(@RequestBody Map mp) {
        String userid = MiscUtil.verifyToken(mp.get("access_token").toString());
        if (userid == null) {
            return new ReturnData(200, "nothing", null);
        } else {
            List<SongSubinfo> maps = songService.queryByUserid(Integer.parseInt(userid));
            return new ReturnData(200, "获取成功", maps);
        }
    }

    @RequestMapping("getusersongs")
    ReturnData getusersongs(@RequestBody Map mp) {
        List<SongSubinfo> maps = songService.queryByUserid(Integer.parseInt(mp.get("user_id").toString()));
        return new ReturnData(200, "获取成功", maps);
    }

    @RequestMapping("deleteMySong")
    ReturnData deleteMySong(@RequestBody Map mp) {
        String userid = MiscUtil.verifyToken(mp.get("access_token").toString());
        if (userid == null) {
            return new ReturnData(403, "没权限QWQ", null);
        } else {
            /*int update = jdbcTemplate.update("DELETE FROM  subscribeinfo WHERE mid=? and user_id=? ", mp.get("mid"), userid);*/
            Boolean update = subscribeinfoService.delete(Integer.parseInt(mp.get("mid").toString()), Integer.parseInt(userid));
            if (update) {
                return new ReturnData(200, "成功", null);
            }
            return new ReturnData(403, "失败", null);
        }
    }

    @RequestMapping("remove")
    ReturnData removesong(@RequestBody JSONObject mp) {
        String access_token = mp.get("access_token").toString();
        String s = MiscUtil.verifyToken(access_token);
        Object room_id = mp.get("room_id");
        if (s == null) {
            return new ReturnData(403, "无权删除", null);
        } else {
            if (removebymid(room_id.toString(), mp.getLong("mid"))) {
                JSONObject message = new JSONObject();
                message.put("type", "removeSong");
                message.put("user", userinfoService.queryById(Integer.parseInt(s)));
                message.put("song", querybyid(mp.get("mid")));
                messageinfoService.sendMessage(room_id.toString(), message.toJSONString());
                return new ReturnData(200, "删除成功", null);
            } else {
                return new ReturnData(403, "删除失败", null);
            }
        }
    }

    private static ConcurrentHashMap<String, ConcurrentHashSet<String>> nowpass = new ConcurrentHashMap<>();

    @RequestMapping("pass")
    ReturnData passsong(@RequestBody JSONObject mp) {
        String access_token = MiscUtil.verifyToken(mp.get("access_token").toString());
        if (access_token == null) {
            return new ReturnData(401, "无权切歌!", null);
        }
        String room_id = mp.get("room_id").toString();
        Roominfo roominfo = roominfoService.queryById(mp.getInteger("room_id"));
        BoundListOperations roomops = redisTemplate.boundListOps(room_id);
        if (roomops.size() <= 1) {
            return new ReturnData(200, "没有下一首了qwq", null);
        } else if (roominfo.getRoom_votepass() != null && roominfo.getRoom_votepass() != -1) {
            if (nowpass.get(room_id) == null) {
                nowpass.put(room_id, new ConcurrentHashSet<>());
            }
            boolean contains = nowpass.get(room_id).contains(access_token);
            if (contains) {
                return new ReturnData(200, "你不想表态的态度成功", null);
            }
            nowpass.get(room_id).add(access_token);
            int size = core.CHATMAP.get(room_id).size();
            if (nowpass.get(room_id).size() < Math.ceil(size * 1.0 * roominfo.getRoom_votepass() / 100)) {//未达到要求
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("content", "有人表示不太喜欢当前播放的歌(" + nowpass.size() + "/" + size + ")");
                jsonObject.put("time", new Date());
                jsonObject.put("type", "system");
                messageinfoService.sendMessage(room_id, jsonObject.toJSONString());
                return new ReturnData(200, "你不想表态的态度成功", null);
            } else {
                nowpass.put(room_id, new ConcurrentHashSet<>());
            }
        }

        roomops.leftPop();
        SongTask.channelhome.put(room_id, System.currentTimeMillis());
        JSONObject jnow = JSON.parseObject(roomops.index(0).toString());
        jnow.put("since", System.currentTimeMillis() / 1000);
        jnow.put("type", "playSong");
        messageinfoService.sendMessage(room_id, jnow.toJSONString());
        return new ReturnData(200, "成功", null);


    }


    @RequestMapping("push")
    public ReturnData pushsong(@RequestBody JSONObject mp) {
        String access_token = MiscUtil.verifyToken(mp.get("access_token").toString());
        Integer room_id = mp.getInteger("room_id");
        Roominfo roominfo = roominfoService.queryById(room_id);
        if (access_token == null) {
            return new ReturnData(403, "无权顶歌!", null);
        }
        if (roominfo.getRoom_pushdaycount() != null && roominfo.getRoom_pushdaycount() != -1) {
            BoundHashOperations pushdaycount = redisTemplate.boundHashOps("pushdaycount");
            HashMap<Integer, Long> res = (HashMap<Integer, Long>) pushdaycount.get(room_id);
            Long aLong = 0L;
            if (res == null) {
                res = new HashMap<>();
            } else {
                aLong = res.get(Integer.parseInt(access_token));
                if (aLong + 1 > roominfo.getRoom_pushdaycount()) {
                    return new ReturnData(403, "今天不能再顶了", null);
                }
            }
            res.put(Integer.parseInt(access_token), aLong + 1);
            pushdaycount.put(room_id, res);
        }
        if (roominfo.getRoom_pushsongcd() != null && roominfo.getRoom_pushsongcd() != -1) {
            BoundHashOperations pushsongcd = redisTemplate.boundHashOps("pushsongcd");
            HashMap<Integer, Long> res = (HashMap<Integer, Long>) pushsongcd.get(room_id);
            if (res == null) {
                res = new HashMap<>();
            } else if (res.get(room_id) != null) {
                Long cd = res.get(room_id);
                if (roominfo.getRoom_pushsongcd() * 1000 + cd >= System.currentTimeMillis()) {
                    return new ReturnData(403, "终极技能 顶歌 还有 " + (roominfo.getRoom_pushsongcd() * 1000 + cd - System.currentTimeMillis()) / 1000 + "秒", null);
                }
            }
            res.put(room_id, System.currentTimeMillis());
            pushsongcd.put(room_id, res);
        }
        BoundListOperations boundListOperations = redisTemplate.boundListOps(room_id.toString());
        int pos = getsongpos(room_id.toString(), mp.getLong("mid"));
        if (pos == -1) {
            return new ReturnData(200, "顶歌失败 原因是没有找到这首歌", null);
        }
        JSONObject index1 = JSON.parseObject(boundListOperations.index(1).toString());
        JSONObject index2 = JSON.parseObject(boundListOperations.index(pos).toString());
        boundListOperations.set(pos, index1.toJSONString());
        boundListOperations.set(1, index2.toJSONString());
        JSONObject message = new JSONObject();
        message.put("type", "push");
        message.put("user_name", mp.get("user_name"));
        message.put("song", querybyid(mp.get("mid")));

        messageinfoService.sendMessage(room_id.toString(), message.toJSONString());
        return new ReturnData(200, "顶好了", null);
    }

    //从1开始的原因是 0正在播放 不能对其修改
    boolean removebymid(String room_id, Long mid) {
        BoundListOperations boundListOperations = redisTemplate.boundListOps(room_id);
        List range = boundListOperations.range(0, -1);
        for (int i = 1; i < range.size(); i++) {
            Object t1 = range.get(i);
            JSONObject jsonObject = JSONObject.parseObject(t1.toString());
            Long aLong = jsonObject.getJSONObject("song").getLong("mid");
            if (aLong.equals(mid)) {
                boundListOperations.remove(1, t1);
                return true;
            }
        }
        return false;
    }

    boolean songisexit(String room_id, Long mid) {
        BoundListOperations boundListOperations = redisTemplate.boundListOps(room_id);
        List range = boundListOperations.range(0, -1);
        for (int i = 1; i < range.size(); i++) {
            String t1 = (String) range.get(i);
            JSONObject jsonObject = JSONObject.parseObject(t1);
            Long aLong = jsonObject.getJSONObject("song").getLong("mid");
            if (aLong.equals(mid)) {
                return true;
            }
        }
        return false;
    }

    int getsongpos(String room_id, Long mid) {
        BoundListOperations boundListOperations = redisTemplate.boundListOps(room_id);
        List range = boundListOperations.range(0, -1);
        for (int i = 1; i < range.size(); i++) {
            String t1 = (String) range.get(i);
            JSONObject jsonObject = JSONObject.parseObject(t1);
            Long aLong = jsonObject.getJSONObject("song").getLong("mid");
            if (aLong.equals(mid)) {
                return i;
            }
        }
        return -1;
    }
    @RequestMapping("addNewSong")
    public ReturnData addNewSong(@RequestBody JSONObject body) {
        Songinfo songinfo = new Songinfo();
        songinfo.setMid(body.getLong("song_mid"));
        songinfo.setName(body.getString("song_name"));
        songinfo.setLength(body.getInteger("song_length"));
        songinfo.setHot(0);
        songinfo.setPic(body.getString("song_pic"));
        songinfo.setSinger(body.getString("song_singer"));
        songinfo.setUrl(body.getString("song_url"));
        songService.insert(songinfo);
        return new ReturnData(200, "success", null);
    }

}
